package com.minimalist.common.feign.config;

import feign.Request;
import feign.Response;
import feign.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * 自定义Feign日志记录器
 *
 * @author minimalist
 */
public class CustomFeignLogger extends feign.Logger {
    private static final Logger log = LoggerFactory.getLogger(CustomFeignLogger.class);

    // 限制日志中请求/响应体的最大大小
    private static final int MAX_BODY_SIZE = 8192;
    private static final String FEIGN_REQUEST_ID = "feignRequestId";

    @Override
    protected void log(String configKey, String format, Object... args) {
        // 使用SLF4J记录日志
        if (log.isInfoEnabled()) {
            log.info(String.format(methodTag(configKey) + format, args));
        }
    }

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {
        // 为每个请求生成唯一ID
        String requestId = UUID.randomUUID().toString();
        MDC.put(FEIGN_REQUEST_ID, requestId);

        try {
            // 记录请求信息，包含完整的服务名和路径
            String serviceName = extractServiceName(configKey);
            String fullPath = serviceName + request.url();

            log.info(">>> Feign请求开始 [{}] - {} {} - 完整路径: {}",
                    requestId, request.httpMethod(), request.url(), fullPath);

            // 记录请求头
            if (log.isInfoEnabled()) {
                StringBuilder headers = new StringBuilder();
                request.headers().forEach((name, values) ->
                        values.forEach(value -> headers.append("\n  ").append(name)
                                .append(": ").append(value)));
                log.info(">>> 请求头 [{}]: {}", requestId, headers);
            }

            // 记录请求体
            if (request.body() != null && request.body().length > 0) {
                String bodyText = getBodyAsString(request.body());
                log.info(">>> 请求体 [{}]: {}", requestId, bodyText);
            }
        } catch (Exception e) {
            log.warn("无法记录请求信息: {}", e.getMessage());
        } finally {
            MDC.remove(FEIGN_REQUEST_ID);
        }
    }

    /**
     * 从configKey中提取服务名称
     * configKey格式通常为：类名#方法名(参数类型)
     */
    private String extractServiceName(String configKey) {
        // 从FeignClient注解中获取服务名
        // 这里简单处理，实际可能需要根据您的项目结构调整
        if (configKey.contains("minimalist-lindi")) {
            return "minimalist-lindi";
        } else if (configKey.contains("minimalist-basic")) {
            return "minimalist-basic";
        } else if (configKey.contains("minimalist-tc")) {
            return "minimalist-tc";
        }

        // 从configKey中提取类名部分作为服务标识
        int hashIndex = configKey.indexOf('#');
        if (hashIndex > 0) {
            String className = configKey.substring(0, hashIndex);
            // 尝试从类名中提取服务名
            int lastDotIndex = className.lastIndexOf('.');
            if (lastDotIndex > 0) {
                String simpleName = className.substring(lastDotIndex + 1);
                if (simpleName.contains("FeignClient")) {
                    return simpleName.replace("FeignClient", "");
                }
            }
        }
        return "unknown-service";
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) {
        String requestId = MDC.get(FEIGN_REQUEST_ID);
        if (requestId == null) {
            requestId = UUID.randomUUID().toString();
            MDC.put(FEIGN_REQUEST_ID, requestId);
        }

        try {
            // 记录响应信息
            String serviceName = extractServiceName(configKey);
            String fullPath = serviceName + response.request().url();

            log.info("<<< Feign响应 [{}] - 状态: {} - 耗时: {}ms - 完整路径: {}",
                    requestId, response.status(), elapsedTime, fullPath);

            // 记录响应头
            if (log.isInfoEnabled()) {
                StringBuilder headers = new StringBuilder();
                response.headers().forEach((name, values) ->
                        values.forEach(value -> headers.append("\n  ").append(name)
                                .append(": ").append(value)));
                log.info("<<< 响应头 [{}]: {}", requestId, headers);
            }

            // 克隆响应以便可以多次读取
            byte[] bodyData;
            if (response.body() != null) {
                try {
                    // 正确处理Response.Body
                    bodyData = Util.toByteArray(response.body().asInputStream());
                } catch (IOException e) {
                    log.warn("无法读取响应体: {}", e.getMessage());
                    return response;
                }
            } else {
                bodyData = new byte[0];
            }

            // 记录响应体
            if (bodyData.length > 0) {
                String bodyText = getBodyAsString(bodyData);
                log.info("<<< 响应体 [{}]: {}", requestId, bodyText);
            } else {
                log.info("<<< 响应体 [{}]: 空", requestId);
            }

            // 重新构建响应
            return response.toBuilder()
                    .body(bodyData)
                    .build();
        } finally {
            MDC.remove(FEIGN_REQUEST_ID);
        }
    }

    /**
     * 将字节数组转换为字符串，并限制大小
     */
    private String getBodyAsString(byte[] body) {
        if (body.length == 0) {
            return "空";
        }

        // 限制日志中显示的请求/响应体大小
        int length = Math.min(body.length, MAX_BODY_SIZE);
        String bodyText = new String(body, 0, length, StandardCharsets.UTF_8);

        // 如果内容被截断，添加提示
        if (body.length > MAX_BODY_SIZE) {
            bodyText += "... (内容过长已截断)";
        }

        return bodyText;
    }
}
